package installer

// 移动所有类型定义和方法实现
// Package, Config, ToolsConfig, Installer, PackageNode 等结构体

import (
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"sort"
)

// Package 增加依赖和优先级字段
type Package struct {
	Name         string            `json:"name"`
	Version      string            `json:"version"`
	Tool         string            `json:"tool"`
	Options      map[string]string `json:"options,omitempty"`
	Dependencies []string          `json:"dependencies,omitempty"` // 依赖的包名列表
	Priority     int               `json:"priority"`               // 优先级，数字越小优先级越高
	Group        string            `json:"group,omitempty"`        // 安装组，同组包可以并行安装
}

// Config 配置文件结构
type Config struct {
	Packages    []Package   `json:"packages"`
	ToolsConfig ToolsConfig `json:"toolsConfig"`
}

type ToolsConfig struct {
	BasePath string            `json:"basePath"`
	Tools    map[string]string `json:"tools"`
}

// Installer 安装器结构体
type Installer struct {
	config     *Config
	configPath string
	installed  map[string]bool // 记录已安装的包
}

// PackageNode 用于构建依赖图
type PackageNode struct {
	Package      Package
	Dependencies []*PackageNode
	Visited      bool
	InStack      bool // 用于检测循环依赖
}

// NewInstaller 创建新的安装器实例
func NewInstaller(configPath string) (*Installer, error) {
	installer := &Installer{
		configPath: configPath,
		installed:  make(map[string]bool),
	}

	if err := installer.loadConfig(); err != nil {
		return nil, fmt.Errorf("加载配置文件失败: %w", err)
	}

	return installer, nil
}

// loadConfig 加载配置文件
func (i *Installer) loadConfig() error {
	data, err := os.ReadFile(i.configPath)
	if err != nil {
		return fmt.Errorf("读取配置文件失败: %w", err)
	}

	i.config = &Config{}
	if err := json.Unmarshal(data, i.config); err != nil {
		return fmt.Errorf("解析配置文件失败: %w", err)
	}

	return nil
}

// Install 执行安装过程
func (i *Installer) Install() error {
	// 对包进行排序和分组
	sortedPackages, err := i.sortPackages()
	if err != nil {
		return fmt.Errorf("排序包失败: %w", err)
	}

	// 按组安装包
	for _, group := range i.groupPackages(sortedPackages) {
		if err := i.installGroup(group); err != nil {
			return err
		}
	}

	fmt.Println("所有包安装完成")
	return nil
}

// sortPackages 对包进行拓扑排序
func (i *Installer) sortPackages() ([]Package, error) {
	// 构建依赖图
	nodes := make(map[string]*PackageNode)
	for _, pkg := range i.config.Packages {
		nodes[pkg.Name] = &PackageNode{Package: pkg}
	}

	// 建立依赖关系
	for name, node := range nodes {
		for _, depName := range node.Package.Dependencies {
			if depNode, exists := nodes[depName]; exists {
				node.Dependencies = append(node.Dependencies, depNode)
			} else {
				return nil, fmt.Errorf("包 %s 依赖的包 %s 不存在", name, depName)
			}
		}
	}

	// 执行拓扑排序
	var sorted []Package
	for _, node := range nodes {
		if !node.Visited {
			if err := i.visitNode(node, &sorted); err != nil {
				return nil, err
			}
		}
	}

	// 按优先级进行二次排序
	sort.SliceStable(sorted, func(i, j int) bool {
		return sorted[i].Priority < sorted[j].Priority
	})

	return sorted, nil
}

// visitNode 访问节点（拓扑排序的DFS实现）
func (i *Installer) visitNode(node *PackageNode, sorted *[]Package) error {
	if node.InStack {
		return fmt.Errorf("检测到循环依赖: %s", node.Package.Name)
	}
	if node.Visited {
		return nil
	}

	node.InStack = true
	for _, dep := range node.Dependencies {
		if err := i.visitNode(dep, sorted); err != nil {
			return err
		}
	}
	node.InStack = false
	node.Visited = true
	*sorted = append(*sorted, node.Package)
	return nil
}

// groupPackages 将包按组分组
func (i *Installer) groupPackages(packages []Package) [][]Package {
	groups := make(map[string][]Package)

	// 将包分配到各个组
	for _, pkg := range packages {
		groupName := pkg.Group
		if groupName == "" {
			groupName = pkg.Name // 如果没有指定组，每个包自成一组
		}
		groups[groupName] = append(groups[groupName], pkg)
	}

	// 将分组转换为切片
	var result [][]Package
	for _, group := range groups {
		result = append(result, group)
	}

	return result
}

// installGroup 安装一个组的包
func (i *Installer) installGroup(group []Package) error {
	// 检查组内所有包的依赖是否已安装
	for _, pkg := range group {
		for _, dep := range pkg.Dependencies {
			if !i.installed[dep] {
				return fmt.Errorf("包 %s 的依赖 %s 尚未安装", pkg.Name, dep)
			}
		}
	}

	// 安装组内的包
	for _, pkg := range group {
		if err := i.installPackage(pkg); err != nil {
			return err
		}
		i.installed[pkg.Name] = true
	}

	return nil
}

// installPackage 安装单个包
func (i *Installer) installPackage(pkg Package) error {
	fmt.Printf("正在安装 %s (版本: %s)...\n", pkg.Name, pkg.Version)

	toolPath, err := i.getToolPath(pkg.Tool)
	if err != nil {
		return err
	}

	args := i.buildInstallArgs(pkg)
	cmd := exec.Command(toolPath, args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		return fmt.Errorf("执行安装命令失败: %w", err)
	}

	return nil
}

// buildInstallArgs constructs the installation arguments for a package
func (i *Installer) buildInstallArgs(pkg Package) []string {
	args := []string{"install", pkg.Name + "@" + pkg.Version}
	for key, value := range pkg.Options {
		args = append(args, fmt.Sprintf("--%s=%s", key, value))
	}
	return args
}

// getToolPath returns the full path of the tool
func (i *Installer) getToolPath(toolName string) (string, error) {
	toolPath, exists := i.config.ToolsConfig.Tools[toolName]
	if !exists {
		return "", fmt.Errorf("tool %s not found in configuration", toolName)
	}
	return filepath.Join(i.config.ToolsConfig.BasePath, toolPath), nil
}

// getToolPath 和 buildInstallArgs 方法保持不变...

func main() {
	configPath := flag.String("config", "install.json", "配置文件路径")
	flag.Parse()

	installer, err := NewInstaller(*configPath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "初始化安装器失败: %v\n", err)
		os.Exit(1)
	}

	if err := installer.Install(); err != nil {
		fmt.Fprintf(os.Stderr, "安装失败: %v\n", err)
		os.Exit(1)
	}
}
